#include "daliesque.h"
#include "../metric/xyz.h"
#include <assert.h>
#include "aa_util.h"
#include "../metric/pairwise_distance_neighborhood.h"

void daliesque_constructor(const char* pdbCode,
			   void * neighp,
			   struct store * atomStore,
			   off_t center,
			   off_t neighbors[],
			   short count) {
  struct daliesque * neigh = neighp;
  //void daliesque_constructor(struct daliesque * d, struct xyz_int * center, unsigned char center_type_index, 
  //			   struct xyz_int neighbors[], unsigned char neighbor_type_indices[], size_t count) {
  

  struct xyz_int center_xyz; 
  struct xyz_int neighbor_xyz[DALI_COUNT];

  struct atom * a;

  off_t start, stop;

  short i;

  short * sorted = malloc(sizeof(short) * count);

  assert(count == DALI_COUNT);

  find_aa_range(atomStore, center, &start, &stop);
  
  calculate_aa_mass_center(atomStore, start, stop, &center_xyz);

  for(i = 0; i < count && neighbors[i] != -1; i++) {
    find_aa_range(atomStore, neighbors[i], &start, &stop);
    calculate_aa_mass_center(atomStore, start, stop, &(neighbor_xyz[i]));
  }

  a = store_read(atomStore, center);

  neigh->aa_residue_serial = a->residue;
  neigh->chain = a->chain;
  store_release(atomStore, center);
  strncpy(neigh->pdbStructure, pdbCode, 4);

  pairwise_distance_neighborhood_calculate( ((struct daliesque*)neigh) ->paird, sorted, &center_xyz, (char*)neighbor_xyz, DALI_COUNT, sizeof(struct xyz_int), (double(*)(const void*,const void*))xyz_int_distance);

  //  daliesque_print_thorough(neigh, 0);
  free(sorted);



  /*  d->aa_indices[0] = center_type_index;
  for(i = 0; i < DALI_COUNT; i++) {
    d->aa_indices[i+1] = neighbor_type_indices[i]; 
    }*/
}

double daliesque_distance(struct daliesque * d1, struct daliesque * d2) {
  double ret = 0.0;
  ret = pairwise_distance_neighborhood_distances(d1->paird, d2->paird, pairwise_distance_neighborhood_get_array_size(DALI_COUNT));

  /*  for(i = 0; i < DALI_COUNT+1; i++) {
      ret += aa_type_distances(d1->aa_indices[i], d2->aa_indices[i]);
      }*/
  return ret;
}


int daliesque_can_calculate_neighborhood(struct store * s, off_t i) {
  off_t start, stop;

  find_aa_range(s,i,&start,&stop);

  return can_calculate_aa_mass_center(s, start, stop);

}

const void * daliesque_print(const void * dp, void * store) {
  const struct daliesque * d = dp;
  printf("%.4s\t%c\t%d\n", d->pdbStructure, d->chain, d->aa_residue_serial);

  return d;
}

void * daliesque_print_thorough(struct daliesque * d, void * store) {
  int i;
  printf("%.4s\t%d [", d->pdbStructure, d->aa_residue_serial);

  for(i = 0; i < (DALI_COUNT*(DALI_COUNT+1))/2; i++) {
    printf("\t%d", d->paird[i]);
  }
  
  printf ("]\n");
  return d;
}
